package com.lwl.concurrency.synchr;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 锁的中断响应,当两个线程产生死锁后,一方中断,另一方获取到锁完成任务
 * 线程1获取锁1, 线程2获取锁2
 线程1执行完成后获取锁2,但是锁2还没有被线程2释放,线程2执行完成后又去获取锁1
 锁1被线程1占用,最后导致死锁.
 两秒后: 线程2中断,取消了对锁1的竞争,同时释放了锁2,最后线程1获取到锁2,最后完成任务.
 *
 * @author liwenlong - 2018/3/27 16:56
 */
public class LockInterruptiblyTest implements Runnable {

    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();

    int lock;

    /**
     * 控制加锁顺序,方便构造死锁
     *
     * @param lock
     */
    public LockInterruptiblyTest(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            if (lock == 1) {
                System.out.println("lock 1 start...");
                lock1.lockInterruptibly();
                Thread.sleep(500);
                System.out.println("lock 1 run...");
                lock2.lockInterruptibly();
                System.out.println("lock 1 end...");
            } else {
                System.out.println("lock 2 start...");
                lock2.lockInterruptibly();
                Thread.sleep(500);
                System.out.println("lock 2 run...");
                lock1.lockInterruptibly();
                System.out.println("lock 2 end...");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock1.isHeldByCurrentThread()) {
                lock1.unlock();
                System.out.println("锁1释放");
            }
            if (lock2.isHeldByCurrentThread()) {
                lock2.unlock();
                System.out.println("锁2释放");
            }
            System.out.println(Thread.currentThread().getName() + ":退出");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        /*
        线程1获取锁1, 线程2获取锁2
        线程1执行完成后获取锁2,但是锁2还没有被线程2释放,线程2执行完成后又去获取锁1
        锁1被线程1占用,最后导致死锁.
        两秒后: 线程2中断,取消了对锁1的竞争,同时释放了锁2,最后线程1获取到锁2,最后完成任务.
         */
        LockInterruptiblyTest r1 = new LockInterruptiblyTest(1);
        LockInterruptiblyTest r2 = new LockInterruptiblyTest(2);

        Thread thread1 = new Thread(r1);
        Thread thread2 = new Thread(r2);
        thread1.start();
        thread2.start();

        Thread.sleep(2000);
        //中断线程2
        thread2.interrupt();
    }
}
